;;;
;;; unix/errors.lisp - Error handling for the unix interface
;;;

(in-package :opsys-unix)

(declaim #.`(optimize ,.(getf opsys-config::*config* :optimization-settings)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Error handling

#+(or darwin linux freebsd netbsd openbsd) (config-feature :os-t-has-strerror-r)
#| #+() What systems don't have sys-nerr? |#
;; glibc made this hidden so we can't really use it, but see dlib-i
(config-feature :os-t-has-sys-nerr)

(eval-when (:compile-toplevel :load-toplevel :execute)
  ;; OpenBSD and FreeBSD both have a differently named errno function,
  ;; instead of a variable.
  #+(or openbsd freebsd netbsd)
  (progn
    #+(or openbsd netbsd)
    (defcfun ("__errno" errno-func) (:pointer :int))
    #+freebsd
    (defcfun ("__error" errno-func) (:pointer :int))

    (defun %errno ()
      (let ((p (errno-func)))
	(when (not (null-pointer-p p))
	  (mem-ref p :int))))
    (defun %set-errno (value)
      (let ((p (errno-func)))
	(when (not (null-pointer-p p))
	  (setf (mem-ref p :int) value))))
    (defsetf %errno %set-errno)
    (define-symbol-macro *errno* (%errno))
    (defun errno () (%errno))
    (config-feature :os-t-has-errno-func))

  #-(or openbsd freebsd netbsd)
  (if (foreign-symbol-pointer "__errno_location")
      (progn
	(defcfun ("__errno_location" errno-func) (:pointer :int))
	(defun %errno ()
	  (let ((p (errno-func)))
	    (when (not (null-pointer-p p))
	      (mem-ref p :int))))
	(defun %set-errno (value)
	  (let ((p (errno-func)))
	    (when (not (null-pointer-p p))
	      (setf (mem-ref p :int) value))))
	;; (defsetf %errno get-errno set-errno)
	(defsetf %errno %set-errno)
	(define-symbol-macro *errno* (%errno))
	(defun errno () (%errno))
	(config-feature :os-t-has-errno-func))
      (progn
	(defcvar ("errno" *errno*) :int)
	(defun %set-errno (value) ;; fake, but used by internal things
	  (setf *errno* value))
	(defun errno () *errno*))))

(defparameter *errors* nil)

#+darwin
(define-to-list *errors*
    #(
  #(+EPERM+              1 "Operation not permitted")
  #(+ENOENT+             2 "No such file or directory")
  #(+ESRCH+              3 "No such process")
  #(+EINTR+              4 "Interrupted system call")
  #(+EIO+                5 "Input/output error")
  #(+ENXIO+              6 "Device not configured")
  #(+E2BIG+              7 "Argument list too long")
  #(+ENOEXEC+            8 "Exec format error")
  #(+EBADF+              9 "Bad file descriptor")
  #(+ECHILD+             10 "No child processes")
  #(+EDEADLK+            11 "Resource deadlock avoided")
  #(+ENOMEM+             12 "Cannot allocate memory")
  #(+EACCES+             13 "Permission denied")
  #(+EFAULT+             14 "Bad address")
  #(+ENOTBLK+            15 "Block device required")
  #(+EBUSY+              16 "Device / Resource busy")
  #(+EEXIST+             17 "File exists")
  #(+EXDEV+              18 "Cross-device link")
  #(+ENODEV+             19 "Operation not supported by device")
  #(+ENOTDIR+            20 "Not a directory")
  #(+EISDIR+             21 "Is a directory")
  #(+EINVAL+             22 "Invalid argument")
  #(+ENFILE+             23 "Too many open files in system")
  #(+EMFILE+             24 "Too many open files")
  #(+ENOTTY+             25 "Inappropriate ioctl for device")
  #(+ETXTBSY+            26 "Text file busy")
  #(+EFBIG+              27 "File too large")
  #(+ENOSPC+             28 "No space left on device")
  #(+ESPIPE+             29 "Illegal seek")
  #(+EROFS+              30 "Read-only file system")
  #(+EMLINK+             31 "Too many links")
  #(+EPIPE+              32 "Broken pipe")
  #(+EDOM+               33 "Numerical argument out of domain")
  #(+ERANGE+             34 "Result too large")
  #(+EAGAIN+             35 "Resource temporarily unavailable")
  #(+EWOULDBLOCK+        +EAGAIN+ "Operation would block")
  #(+EINPROGRESS+        36 "Operation now in progress")
  #(+EALREADY+           37 "Operation already in progress")
  #(+ENOTSOCK+           38 "Socket operation on non-socket")
  #(+EDESTADDRREQ+       39 "Destination address required")
  #(+EMSGSIZE+           40 "Message too long")
  #(+EPROTOTYPE+         41 "Protocol wrong type for socket")
  #(+ENOPROTOOPT+        42 "Protocol not available")
  #(+EPROTONOSUPPORT+    43 "Protocol not supported")
  #(+ESOCKTNOSUPPORT+    44 "Socket type not supported")
  #(+ENOTSUP+            45 "Operation not supported")
  ;#(+EOPNOTSUPP+ +ENOTSUP+ "Operation not supported on socket")
  #(+EPFNOSUPPORT+       46 "Protocol family not supported")
  #(+EAFNOSUPPORT+       47 "Address family not supported by protocol family")
  #(+EADDRINUSE+         48 "Address already in use")
  #(+EADDRNOTAVAIL+      49 "Can't assign requested address")
  #(+ENETDOWN+           50 "Network is down")
  #(+ENETUNREACH+        51 "Network is unreachable")
  #(+ENETRESET+          52 "Network dropped connection on reset")
  #(+ECONNABORTED+       53 "Software caused connection abort")
  #(+ECONNRESET+         54 "Connection reset by peer")
  #(+ENOBUFS+            55 "No buffer space available")
  #(+EISCONN+            56 "Socket is already connected")
  #(+ENOTCONN+           57 "Socket is not connected")
  #(+ESHUTDOWN+          58 "Can't send after socket shutdown")
  #(+ETOOMANYREFS+       59 "Too many references: can't splice")
  #(+ETIMEDOUT+          60 "Operation timed out")
  #(+ECONNREFUSED+       61 "Connection refused")
  #(+ELOOP+              62 "Too many levels of symbolic links")
  #(+ENAMETOOLONG+       63 "File name too long")
  #(+EHOSTDOWN+          64 "Host is down")
  #(+EHOSTUNREACH+       65 "No route to host")
  #(+ENOTEMPTY+          66 "Directory not empty")
  #(+EPROCLIM+           67 "Too many processes")
  #(+EUSERS+             68 "Too many users")
  #(+EDQUOT+             69 "Disc quota exceeded")
  #(+ESTALE+             70 "Stale NFS file handle")
  #(+EREMOTE+            71 "Too many levels of remote in path")
  #(+EBADRPC+            72 "RPC struct is bad")
  #(+ERPCMISMATCH+       73 "RPC version wrong")
  #(+EPROGUNAVAIL+       74 "RPC prog. not avail")
  #(+EPROGMISMATCH+      75 "Program version wrong")
  #(+EPROCUNAVAIL+       76 "Bad procedure for program")
  #(+ENOLCK+             77 "No locks available")
  #(+ENOSYS+             78 "Function not implemented")
  #(+EFTYPE+             79 "Inappropriate file type or format")
  #(+EAUTH+              80 "Authentication error")
  #(+ENEEDAUTH+          81 "Need authenticator")
  #(+EPWROFF+            82 "Device power is off")
  #(+EDEVERR+            83 "Device error, e.g. paper out")
  #(+EOVERFLOW+          84 "Value too large to be stored in data type")
  #(+EBADEXEC+           85 "Bad executable")
  #(+EBADARCH+           86 "Bad CPU type in executable")
  #(+ESHLIBVERS+         87 "Shared library version mismatch")
  #(+EBADMACHO+          88 "Malformed Macho file")
  #(+ECANCELED+          89 "Operation canceled")
  #(+EIDRM+              90 "Identifier removed")
  #(+ENOMSG+             91 "No message of desired type */")
  #(+EILSEQ+             92 "Illegal byte sequence")
  #(+ENOATTR+            93 "Attribute not found")
  #(+EBADMSG+            94 "Bad message")
  #(+EMULTIHOP+          95 "Reserved")
  #(+ENODATA+            96 "No message available on STREAM")
  #(+ENOLINK+            97 "Reserved")
  #(+ENOSR+              98 "No STREAM resources")
  #(+ENOSTR+             99 "Not a STREAM")
  #(+EPROTO+             100 "Protocol error")
  #(+ETIME+              101 "STREAM ioctl timeout")
  #(+EOPNOTSUPP+         102 "Operation not supported on socket")
  #(+ENOPOLICY+          103 "No such policy registered")
  #(+ELAST+              103 "Must be equal largest errno")
      ))

#+sunos
(define-to-list *errors*
    #(
  #(+EPERM+	 1	"Not super-user")
  #(+ENOENT+	 2	"No such file or directory")
  #(+ESRCH+	 3	"No such process")
  #(+EINTR+	 4	"Interrupted system call")
  #(+EIO+	 5	"I/O error")
  #(+ENXIO+	 6	"No such device or address")
  #(+E2BIG+	 7	"Arg list too long")
  #(+ENOEXEC+	 8	"Exec format error")
  #(+EBADF+	 9	"Bad file number")
  #(+ECHILD+	 10	"No children")
  #(+EAGAIN+	 11	"Resource temporarily unavailable")
  #(+ENOMEM+	 12	"Not enough core")
  #(+EACCES+	 13	"Permission denied")
  #(+EFAULT+	 14	"Bad address")
  #(+ENOTBLK+	 15	"Block device required")
  #(+EBUSY+	 16	"Mount device busy")
  #(+EEXIST+	 17	"File exists")
  #(+EXDEV+	 18	"Cross-device link")
  #(+ENODEV+	 19	"No such device")
  #(+ENOTDIR+	 20	"Not a directory")
  #(+EISDIR+	 21	"Is a directory")
  #(+EINVAL+	 22	"Invalid argument")
  #(+ENFILE+	 23	"File table overflow")
  #(+EMFILE+	 24	"Too many open files")
  #(+ENOTTY+	 25	"Inappropriate ioctl for device")
  #(+ETXTBSY+	 26	"Text file busy")
  #(+EFBIG+	 27	"File too large")
  #(+ENOSPC+	 28	"No space left on device")
  #(+ESPIPE+	 29	"Illegal seek")
  #(+EROFS+	 30	"Read only file system")
  #(+EMLINK+	 31	"Too many links")
  #(+EPIPE+	 32	"Broken pipe")
  #(+EDOM+	 33	"Math arg out of domain of func")
  #(+ERANGE+	 34	"Math result not representable")
  #(+ENOMSG+	 35	"No message of desired type")
  #(+EIDRM+	 36	"Identifier removed")
  #(+ECHRNG+	 37	"Channel number out of range")
  #(+EL2NSYNC+   38	"Level 2 not synchronized")
  #(+EL3HLT+	 39	"Level 3 halted")
  #(+EL3RST+	 40	"Level 3 reset")
  #(+ELNRNG+	 41	"Link number out of range")
  #(+EUNATCH+    42	"Protocol driver not attached")
  #(+ENOCSI+	 43	"No CSI structure available")
  #(+EL2HLT+	 44	"Level 2 halted")
  #(+EDEADLK+	 45	"Deadlock condition.")
  #(+ENOLCK+	 46	"No record locks available.")
  #(+ECANCELED+  47	"Operation canceled")
  #(+ENOTSUP+	 48	"Operation not supported")
  ;; Filesystem Quotas
  #(+EDQUOT+	 49	"Disc quota exceeded")
  ;; Convergent Error Returns
  #(+EBADE+	 50	"invalid exchange")
  #(+EBADR+	 51	"invalid request descriptor")
  #(+EXFULL+	 52	"exchange full")
  #(+ENOANO+	 53	"no anode")
  #(+EBADRQC+	 54	"invalid request code")
  #(+EBADSLT+	 55	"invalid slot")
  #(+EDEADLOCK+	 56	"file locking deadlock error")

  #(+EBFONT+	 57	"bad font file fmt")

  ;; Interprocess Robust Locks
  #(+EOWNERDEAD+	58	"process died with the lock")
  #(+ENOTRECOVERABLE+	59	"lock is not recoverable")

  ;; stream problems
  #(+ENOSTR+	60	"Device not a stream")
  #(+ENODATA+	61	"no data (for no delay io)")
  #(+ETIME+	62	"timer expired")
  #(+ENOSR+	63	"out of streams resources")

  #(+ENONET+	64	"Machine is not on the network")
  #(+ENOPKG+	65	"Package not installed")
  #(+EREMOTE+	66	"The object is remote")
  #(+ENOLINK+	67	"the link has been severed")
  #(+EADV+	68	"advertise error")
  #(+ESRMNT+	69	"srmount error")

  #(+ECOMM+	70	"Communication error on send")
  #(+EPROTO+	71	"Protocol error")

  ;; Interprocess Robust Locks
  #(+ELOCKUNMAPPED+ 72 "locked lock was unmapped")

  #(+ENOTACTIVE+   73 "Facility is not active")
  #(+EMULTIHOP+    74 "multihop attempted")
  #(+EBADMSG+      77 "trying to read unreadable message")
  #(+ENAMETOOLONG+ 78 "path name is too long")
  #(+EOVERFLOW+    79 "value too large to be stored in data type")
  #(+ENOTUNIQ+     80 "given log. name not unique")
  #(+EBADFD+	   81 "f.d. invalid for this operation")
  #(+EREMCHG+	   82 "Remote address changed")

  ;; shared library problems
  #(+ELIBACC+	   83 "Can't access a needed shared lib.")
  #(+ELIBBAD+	   84 "Accessing a corrupted shared lib.")
  #(+ELIBSCN+	   85 ".lib section in a.out corrupted.")
  #(+ELIBMAX+	   86 "Attempting to link in too many libs.")
  #(+ELIBEXEC+	   87 "Attempting to exec a shared library.")
  #(+EILSEQ+	   88 "Illegal byte sequence.")
  #(+ENOSYS+	   89 "Unsupported file system operation")
  #(+ELOOP+	   90 "Symbolic link loop")
  #(+ERESTART+	   91 "Restartable system call")
  #(+ESTRPIPE+	   92 "if pipe/FIFO, don't sleep in stream head")
  #(+ENOTEMPTY+	   93 "directory not empty")
  #(+EUSERS+	   94 "Too many users (for UFS)")

  ;; BSD Networking Software
  ;;    argument errors
  #(+ENOTSOCK+	      95  "Socket operation on non-socket")
  #(+EDESTADDRREQ+    96  "Destination address required")
  #(+EMSGSIZE+	      97  "Message too long")
  #(+EPROTOTYPE+      98  "Protocol wrong type for socket")
  #(+ENOPROTOOPT+     99  "Protocol not available")
  #(+EPROTONOSUPPORT+ 120 "Protocol not supported")
  #(+ESOCKTNOSUPPORT+ 121 "Socket type not supported")
  #(+EOPNOTSUPP+      122 "Operation not supported on socket")
  #(+EPFNOSUPPORT+    123 "Protocol family not supported")
  #(+EAFNOSUPPORT+    124 "Address family not supported by protocol family")
  #(+EADDRINUSE+      125 "Address already in use")
  #(+EADDRNOTAVAIL+   126 "Can't assign requested address")
  ;; operational errors
  #(+ENETDOWN+	      127 "Network is down")
  #(+ENETUNREACH+     128 "Network is unreachable")
  #(+ENETRESET+	      129 "Network dropped connection because of reset")
  #(+ECONNABORTED+    130 "Software caused connection abort")
  #(+ECONNRESET+      131 "Connection reset by peer")
  #(+ENOBUFS+	      132 "No buffer space available")
  #(+EISCONN+	      133 "Socket is already connected")
  #(+ENOTCONN+	      134 "Socket is not connected")
  ;; XENIX has 135 - 142
  #(+ESHUTDOWN+	      143 "Can't send after socket shutdown")
  #(+ETOOMANYREFS+    144 "Too many references: can't splice")
  #(+ETIMEDOUT+	      145 "Connection timed out")
  #(+ECONNREFUSED+    146 "Connection refused")
  #(+EWOULDBLOCK+     +EAGAIN+ "Operation would block")
  #(+EHOSTDOWN+	      147 "Host is down")
  #(+EHOSTUNREACH+    148 "No route to host")
  #(+EALREADY+	      149 "operation already in progress")
  #(+EINPROGRESS+     150 "operation now in progress")

  ;; SUN Network File System 
  #(+ESTALE+	     151 "Stale NFS file handle")))

#+linux
(define-to-list *errors*
    #(#(+EPERM+     1 "Not super-user")
      #(+ENOENT+    2 "No such file or directory")
      #(+ESRCH+     3 "No such process")
      #(+EINTR+     4 "Interrupted system call")
      #(+EIO+       5 "I/O error")
      #(+ENXIO+     6 "No such device or address")
      #(+E2BIG+     7 "Arg list too long")
      #(+ENOEXEC+   8 "Exec format error")
      #(+EBADF+     9 "Bad file number")
      #(+ECHILD+    10 "No children")
      #(+EAGAIN+    11 "Resource temporarily unavailable")
      #(+ENOMEM+    12 "Not enough core")
      #(+EACCES+    13 "Permission denied")
      #(+EFAULT+    14 "Bad address")
      #(+ENOTBLK+   15 "Block device required")
      #(+EBUSY+     16 "Mount device busy")
      #(+EEXIST+    17 "File exists")
      #(+EXDEV+     18 "Cross-device link")
      #(+ENODEV+    19 "No such device")
      #(+ENOTDIR+   20 "Not a directory")
      #(+EISDIR+    21 "Is a directory")
      #(+EINVAL+    22 "Invalid argument")
      #(+ENFILE+    23 "File table overflow")
      #(+EMFILE+    24 "Too many open files")
      #(+ENOTTY+    25 "Inappropriate ioctl for device")
      #(+ETXTBSY+   26 "Text file busy")
      #(+EFBIG+     27 "File too large")
      #(+ENOSPC+    28 "No space left on device")
      #(+ESPIPE+    29 "Illegal seek")
      #(+EROFS+     30 "Read only file system")
      #(+EMLINK+    31 "Too many links")
      #(+EPIPE+     32 "Broken pipe")
      #(+EDOM+      33 "Math arg out of domain of func")
      #(+ERANGE+    34 "Math result not representable")
      #(+ENOMSG+    35 "No message of desired type")
      #(+EIDRM+     36 "Identifier removed")
      #(+ECHRNG+    37 "Channel number out of range")
      #(+EL2NSYNC+  38 "Level 2 not synchronized")
      #(+EL3HLT+    39 "Level 3 halted")
      #(+EL3RST+    40 "Level 3 reset")
      #(+ELNRNG+    41 "Link number out of range")
      #(+EUNATCH+   42 "Protocol driver not attached")
      #(+ENOCSI+    43 "No CSI structure available")
      #(+EL2HLT+    44 "Level 2 halted")
      #(+EDEADLK+   45 "Deadlock condition.")
      #(+ENOLCK+    46 "No record locks available.")
      #(+ECANCELED+ 47 "Operation canceled")
      #(+ENOTSUP+   48 "Operation not supported")

      ;; Filesystem Quotas
      #(+EDQUOT+    49 "Disc quota exceeded")

      ;; Convergent Error Returns
      #(+EBADE+     50 "invalid exchange")
      #(+EBADR+     51 "invalid request descriptor")
      #(+EXFULL+    52 "exchange full")
      #(+ENOANO+    53 "no anode")
      #(+EBADRQC+   54 "invalid request code")
      #(+EBADSLT+   55 "invalid slot")
      #(+EDEADLOCK+ 56 "file locking deadlock error")

      #(+EBFONT+    57 "bad font file fmt")

      ;; Interprocess Robust Locks
      #(+EOWNERDEAD+ 58 "process died with the lock")
      #(+ENOTRECOVERABLE+ 59 "lock is not recoverable")

      ;; stream problems
      #(+ENOSTR+    60 "Device not a stream")
      #(+ENODATA+   61 "no data (for no delay io)")
      #(+ETIME+     62 "timer expired")
      #(+ENOSR+     63 "out of streams resources")

      #(+ENONET+    64 "Machine is not on the network")
      #(+ENOPKG+    65 "Package not installed")
      #(+EREMOTE+   66 "The object is remote")
      #(+ENOLINK+   67 "the link has been severed")
      #(+EADV+      68 "advertise error")
      #(+ESRMNT+    69 "srmount error")

      #(+ECOMM+     70 "Communication error on send")
      #(+EPROTO+    71 "Protocol error")

      ;; Interprocess Robust Locks
      #(+ELOCKUNMAPPED+ 72 "locked lock was unmapped")

      #(+ENOTACTIVE+ 73 "Facility is not active")
      #(+EMULTIHOP+ 74 "multihop attempted")
      #(+EBADMSG+   77 "trying to read unreadable message")
      #(+ENAMETOOLONG+ 78 "path name is too long")
      #(+EOVERFLOW+ 79 "value too large to be stored in data type")
      #(+ENOTUNIQ+  80 "given log. name not unique")
      #(+EBADFD+    81 "f.d. invalid for this operation")
      #(+EREMCHG+   82 "Remote address changed")

      ;; shared library problems
      #(+ELIBACC+   83 "Can't access a needed shared lib.")
      #(+ELIBBAD+   84 "Accessing a corrupted shared lib.")
      #(+ELIBSCN+   85 ".lib section in a.out corrupted.")
      #(+ELIBMAX+   86 "Attempting to link in too many libs.")
      #(+ELIBEXEC+  87 "Attempting to exec a shared library.")
      #(+EILSEQ+    88 "Illegal byte sequence.")
      #(+ENOSYS+    89 "Unsupported file system operation")
      #(+ELOOP+     90 "Symbolic link loop")
      #(+ERESTART+  91 "Restartable system call")
      #(+ESTRPIPE+  92 "if pipe/FIFO, don't sleep in stream head")
      #(+ENOTEMPTY+ 93 "directory not empty")
      #(+EUSERS+    94 "Too many users (for UFS)")

      ;; BSD Networking Software
      ;; argument errors
      #(+ENOTSOCK+          95 "Socket operation on non-socket")
      #(+EDESTADDRREQ+      96 "Destination address required")
      #(+EMSGSIZE+          97 "Message too long")
      #(+EPROTOTYPE+        98 "Protocol wrong type for socket")
      #(+ENOPROTOOPT+       99 "Protocol not available")
      #(+EPROTONOSUPPORT+   120 "Protocol not supported")
      #(+ESOCKTNOSUPPORT+   121 "Socket type not supported")
      #(+EOPNOTSUPP+        122 "Operation not supported on socket")
      #(+EPFNOSUPPORT+      123 "Protocol family not supported")
      #(+EAFNOSUPPORT+      124 "Address family not supported by protocol family")
      #(+EADDRINUSE+        125 "Address already in use")
      #(+EADDRNOTAVAIL+     126 "Can't assign requested address")
      ;; operational errors
      #(+ENETDOWN+          127 "Network is down")
      #(+ENETUNREACH+       128 "Network is unreachable")
      #(+ENETRESET+         129 "Network dropped connection because of reset")
      #(+ECONNABORTED+      130 "Software caused connection abort")
      #(+ECONNRESET+        131 "Connection reset by peer")
      #(+ENOBUFS+           132 "No buffer space available")
      #(+EISCONN+           133 "Socket is already connected")
      #(+ENOTCONN+          134 "Socket is not connected")
      ;; XENIX has 135 - 142
      #(+ESHUTDOWN+         143 "Can't send after socket shutdown")
      #(+ETOOMANYREFS+      144 "Too many references: can't splice")
      #(+ETIMEDOUT+         145 "Connection timed out")
      #(+ECONNREFUSED+      146 "Connection refused")
      #(+EHOSTDOWN+         147 "Host is down")
      #(+EHOSTUNREACH+      148 "No route to host")
      #(+EWOULDBLOCK+       +EAGAIN+ "Operation would block")
      #(+EALREADY+          149 "operation already in progress")
      #(+EINPROGRESS+       150 "operation now in progress")

      ;; Network File System
      #(+ESTALE+            151 "Stale NFS file handle")))

#+(or freebsd openbsd netbsd)
(define-to-list *errors*
    #(#(+EPERM+	          1  "Operation not permitted")
      #(+ENOENT+	  2  "No such file or directory")
      #(+ESRCH+	          3  "No such process")
      #(+EINTR+	          4  "Interrupted system call")
      #(+EIO+	          5  "Input/output error")
      #(+ENXIO+	          6  "Device not configured")
      #(+E2BIG+	          7  "Argument list too long")
      #(+ENOEXEC+	  8  "Exec format error")
      #(+EBADF+	          9  "Bad file descriptor")
      #(+ECHILD+	  10 "No child processes")
      #(+EDEADLK+	  11 "Resource deadlock avoided")
      #(+ENOMEM+	  12 "Cannot allocate memory")
      #(+EACCES+	  13 "Permission denied")
      #(+EFAULT+	  14 "Bad address")
      #(+ENOTBLK+	  15 "Block device required")
      #(+EBUSY+	          16 "Device busy")
      #(+EEXIST+	  17 "File exists")
      #(+EXDEV+	          18 "Cross-device link")
      #(+ENODEV+	  19 "Operation not supported by device")
      #(+ENOTDIR+	  20 "Not a directory")
      #(+EISDIR+	  21 "Is a directory")
      #(+EINVAL+	  22 "Invalid argument")
      #(+ENFILE+	  23 "Too many open files in system")
      #(+EMFILE+	  24 "Too many open files")
      #(+ENOTTY+	  25 "Inappropriate ioctl for device")
      #(+ETXTBSY+	  26 "Text file busy")
      #(+EFBIG+	          27 "File too large")
      #(+ENOSPC+	  28 "No space left on device")
      #(+ESPIPE+	  29 "Illegal seek")
      #(+EROFS+	          30 "Read-only filesystem")
      #(+EMLINK+	  31 "Too many links")
      #(+EPIPE+	          32 "Broken pipe")
      #(+EDOM+	          33 "Numerical argument out of domain")
      #(+ERANGE+	  34 "Result too large")
      #(+EAGAIN+	  35 "Resource temporarily unavailable")
      #(+EWOULDBLOCK+     +EAGAIN+ "Operation would block")
      #(+EINPROGRESS+     36 "Operation now in progress")
      #(+EALREADY+	  37 "Operation already in progress")
      #(+ENOTSOCK+	  38 "Socket operation on non-socket")
      #(+EDESTADDRREQ+    39 "Destination address required")
      #(+EMSGSIZE+	  40 "Message too long")
      #(+EPROTOTYPE+	  41 "Protocol wrong type for socket")
      #(+ENOPROTOOPT+	  42 "Protocol not available")
      #(+EPROTONOSUPPORT+ 43 "Protocol not supported")
      #(+ESOCKTNOSUPPORT+ 44 "Socket type not supported")
      #(+EOPNOTSUPP+	  45 "Operation not supported")
      #(+EPFNOSUPPORT+	  46 "Protocol family not supported")
      #(+EAFNOSUPPORT+	  47 "Address family not supported by protocol family")
      #(+EADDRINUSE+	  48 "Address already in use")
      #(+EADDRNOTAVAIL+	  49 "Can't assign requested address")
      #(+ENETDOWN+	  50 "Network is down")
      #(+ENETUNREACH+	  51 "Network is unreachable")
      #(+ENETRESET+	  52 "Network dropped connection on reset")
      #(+ECONNABORTED+	  53 "Software caused connection abort")
      #(+ECONNRESET+	  54 "Connection reset by peer")
      #(+ENOBUFS+	  55 "No buffer space available")
      #(+EISCONN+	  56 "Socket is already connected")
      #(+ENOTCONN+	  57 "Socket is not connected")
      #(+ESHUTDOWN+	  58 "Can't send after socket shutdown")
      #(+ETOOMANYREFS+	  59 "Too many references: can't splice")
      #(+ETIMEDOUT+	  60 "Operation timed out")
      #(+ECONNREFUSED+	  61 "Connection refused")
      #(+ELOOP+		  62 "Too many levels of symbolic links")
      #(+ENAMETOOLONG+	  63 "File name too long")
      #(+EHOSTDOWN+	  64 "Host is down")
      #(+EHOSTUNREACH+	  65 "No route to host")
      #(+ENOTEMPTY+	  66 "Directory not empty")
      #(+EPROCLIM+	  67 "Too many processes")
      #(+EUSERS+	  68 "Too many users")
      #(+EDQUOT+	  69 "Disc quota exceeded")
      #(+ESTALE+	  70 "Stale NFS file handle")
      #(+EREMOTE+	  71 "Too many levels of remote in path")
      #(+EBADRPC+	  72 "RPC struct is bad")
      #(+ERPCMISMATCH+	  73 "RPC version wrong")
      #(+EPROGUNAVAIL+	  74 "RPC prog. not avail")
      #(+EPROGMISMATCH+	  75 "Program version wrong")
      #(+EPROCUNAVAIL+	  76 "Bad procedure for program")
      #(+ENOLCK+	  77 "No locks available")
      #(+ENOSYS+	  78 "Function not implemented")
      #(+EFTYPE+	  79 "Inappropriate file type or format")
      #(+EAUTH+		  80 "Authentication error")
      #(+ENEEDAUTH+	  81 "Need authenticator")))

;; Where freebsd and openbsd diverge:

#+freebsd
(define-to-list *errors*
    #(#(+ENOTSUP+	  45 "Operation not supported")
      #(+EIDRM+		  82 "Identifier removed")
      #(+ENOMSG+	  83 "No message of desired type")
      #(+EOVERFLOW+	  84 "Value too large to be stored in data type")
      #(+ECANCELED+	  85 "Operation canceled")
      #(+EILSEQ+	  86 "Illegal byte sequence")
      #(+ENOATTR+	  87 "Attribute not found")
      #(+EDOOFUS+	  88 "Programming error")
      #(+EBADMSG+	  89 "Bad message")
      #(+EMULTIHOP+	  90 "Multihop attempted")
      #(+ENOLINK+	  91 "Link has been severed")
      #(+EPROTO+	  92 "Protocol error")
      #(+ENOTCAPABLE+	  93 "Capabilities insufficient")
      #(+ECAPMODE+	  94 "Not permitted in capability mode")
      #(+ENOTRECOVERABLE+ 95 "State not recoverable")
      #(+EOWNERDEAD+	  96 "Previous owner died")
      #(+ELAST+		  96 "Must be equal largest errno")))

#+openbsd
(define-to-list *errors*
    #(#(+EIPSEC+	  82 "IPsec processing failure")
      #(+ENOATTR+	  83 "Attribute not found")
      #(+EILSEQ+	  84 "Illegal byte sequence")
      #(+ENOMEDIUM+	  85 "No medium found")
      #(+EMEDIUMTYPE+	  86 "Wrong medium type")
      #(+EOVERFLOW+	  87 "Value too large to be stored in data type")
      #(+ECANCELED+	  88 "Operation canceled")
      #(+EIDRM+		  89 "Identifier removed")
      #(+ENOMSG+	  90 "No message of desired type")
      #(+ENOTSUP+	  91 "Not supported")
      #(+EBADMSG+	  92 "Bad message")
      #(+ENOTRECOVERABLE+ 93 "State not recoverable")
      #(+EOWNERDEAD+	  94 "Previous owner died")
      #(+EPROTO+	  95 "Protocol error")
      #(+ELAST+		  96 "Must be equal largest errno")))

#+netbsd
(define-to-list *errors*
    #(#(+EIDRM+		  82 "Identifier removed")
      #(+ENOMSG+	  83 "No message of desired type")
      #(+EOVERFLOW+	  84 "Value too large to be stored in data type")
      #(+EILSEQ+	  85 "Illegal byte sequence")
      #(+ENOTSUP+	  86 "Operation not supported")
      #(+ECANCELED+	  87 "Operation canceled")
      #(+EBADMSG+         88 "Bad or Corrupt message")
      #(+ENODATA+         89 "No message available")
      #(+ENOSR+           90 "No STREAM resources")
      #(+ENOSTR+          91 "Not a STREAM")
      #(+ETIME+           92 "STREAM ioctl timeout")
      #(+ENOATTR+         93 "Attribute not found")
      #(+EMULTIHOP+       94 "Multihop attempted *")
      #(+ENOLINK+         95 "Link has been severed")
      #(+EPROTO+          96 "Protocol error")
      #(+ELAST+           96 "Must equal to largest errno")))

#+os-t-has-strerror-r
(defcfun (#+linux "__xpg_strerror_r" #-linux "strerror_r" strerror-r)
    :int (errnum :int) (strerrbuf :pointer) (buflen size-t))
#-os-t-has-strerror-r
(defcvar ("sys_errlist" sys-errlist) :pointer)
#+os-t-has-sys-nerr
(defcvar ("sys_nerr" *sys-nerr*) :int)

(defun strerror (&optional (e *errno*))
  #+os-t-has-strerror-r
  (with-foreign-pointer-as-string (s 100)
    (strerror-r e s 100)) ;; @@@ wrong?!
  #-os-t-has-strerror-r
  (if (< e *sys-nerr*)
      (foreign-string-to-lisp (mem-aref sys-errlist :pointer e))
      (format nil "Unknown error: ~d" e)))

(define-condition posix-error (opsys-error)
  ()
  (:documentation "An error from calling a POSIX function."))

(defun error-message (error-code)
  ;; "Return a string describing the ERROR-CODE."
  (strerror error-code))

(defun error-check (c &optional fmt &rest args)
  "Check if a system call returns an error value and signal it."
  (if (< c 0)
      (error 'posix-error :error-code (errno) ;; *errno*
	     :format-control fmt :format-arguments args)
      c))

(defmacro syscall ((func &rest args))
  "Call a system function and signal a posix-error if it fails."
  `(error-check (,func ,@args)
		;; Actually I think is is a bad idea. Putting the name of the
		;; system call in the error message is misleading. The name of
		;; the system call has nothing to do with the program you are
		;; running, and is just noise. If you want to know where it's
		;; really from, just do a stack trace in the debugger.
		;; Otherwise it's just confusing for the user, even when the
		;; user is me, who usually knows damn well what the stupid
		;; system call should have done.
		;;
		;; ,(concatenate 'string (string-downcase func) ":")
		))

;; End
